<?php
namespace app\admin\jwt;

use app\admin\lib\exception\BaseException;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\SignatureInvalidException;
use think\facade\Cache;
use think\facade\Config;

class MyJwt
{
    private static function getSecretKey(): string
    {
        $key = Config::get('jwt.secret_key');
        if (empty($key)) {
            throw new BaseException([
                'code' => 500,
                'message' => 'JWT配置错误：未在config/jwt.php中设置secret_key',
                'errorCode' => 90001
            ]);
        }
        return $key;
    }

    private static function getExpireTime(): int
    {
        return Config::get('jwt.expire', 7200);
    }

    public static function signToken(array $payload): string
    {
        try {
            $basePayload = [
                'iss' => Config::get('app.name', 'thinkphp6-api'),
                'iat' => time(),
                'nbf' => time(),
                'exp' => time() + self::getExpireTime()
            ];
            $tokenData = array_merge($basePayload, ['data' => $payload]);
            return JWT::encode($tokenData, self::getSecretKey(), 'HS256');
        } catch (\Exception $e) {
            throw new BaseException([
                'code' => 500,
                'message' => 'Token生成失败：' . $e->getMessage(),
                'errorCode' => 90002
            ]);
        }
    }

    public static function checkToken(string $token): array
    {
        try {
            $blacklistKey = 'jwt_blacklist:' . $token;
            if (Cache::store('redis')->has($blacklistKey)) {
                throw new BaseException([
                    'code' => 401,
                    'message' => '令牌已被注销，请重新登录',
                    'errorCode' => 10014
                ]);
            }

            JWT::$leeway = 60;
            $decoded = JWT::decode(
                $token,
                new Key(self::getSecretKey(), 'HS256')
            );

            $decodedArr = (array)$decoded;
            return isset($decodedArr['data']) ? (array)$decodedArr['data'] : [];

        } catch (SignatureInvalidException $e) {
            throw new BaseException([
                'code' => 401,
                'message' => '令牌签名无效（可能被篡改）',
                'errorCode' => 10010
            ]);
        } catch (BeforeValidException $e) {
            throw new BaseException([
                'code' => 401,
                'message' => '令牌尚未生效，请稍后再试',
                'errorCode' => 10011
            ]);
        } catch (ExpiredException $e) {
            throw new BaseException([
                'code' => 401,
                'message' => '令牌已过期，请重新登录',
                'errorCode' => 10012
            ]);
        } catch (\Exception $e) {
            throw new BaseException([
                'code' => 401,
                'message' => '令牌验证失败：' . $e->getMessage(),
                'errorCode' => 10013
            ]);
        }
    }

    public static function addToBlacklist(string $token, ?int $expire = null): void
    {
        try {
            $expireTime = $expire ?? self::getExpireTime();
            $blacklistKey = 'jwt_blacklist:' . $token;
            Cache::store('redis')->set($blacklistKey, 1, $expireTime);
        } catch (\Exception $e) {
            throw new BaseException([
                'code' => 500,
                'message' => 'Token加入黑名单失败：' . $e->getMessage(),
                'errorCode' => 10015
            ]);
        }
    }
}